﻿/**
 * 使用 JSON Data List 创建 Ext 需要的 DataStore
 * @param jsonDataList json 数据列表
 * @param readerConfigOptions 用于 reader 的 config 属性
 * @param recordDef Record的定义
 */
function createMemoryStore(jsonDataList, recordDef, readerConfigOptions) {
    if(!readerConfigOptions) {
        readerConfigOptions = {};
    }
    if (!readerConfigOptions.id) {
        readerConfigOptions.id = 'ID';
    }
//    readerConfigOptions.root = "returnObject";
    return new Ext.data.Store({
        proxy: new Ext.data.MemoryProxy(jsonDataList),
        reader: new Ext.data.JsonReader(readerConfigOptions, recordDef)
    });
}
/**
 * 创建缓存 MemoryStore，应对Grid显示大数据
 * @param jsonDataList
 * @param recordDef
 * @param readerConfigOptions
 */
function createBufferedMemoryStore(jsonDataList, recordDef, readerConfigOptions) {
    // 应该使用 Ext.ux.grid.BufferedStore、Ext.ux.data.BufferedJsonReader 和 MemoryProxy

    if (!readerConfigOptions.id) {
        readerConfigOptions.id = 'ID';
    }
    /**
     * BufferedJsonReader derives from Ext.data.JsonReader and allows to pass
     * a version value representing the current state of the underlying data
     * repository.
     * Version handling on server side is totally up to the user. The version
     * property should change whenever a record gets added or deleted on the server
     * side, so the store can be notified of changes between the previous and current
     * request. If the store notices a version change, it will fire the version change
     * event. Speaking of data integrity: If there are any selections pending,
     * the user can react to this event and cancel all pending selections.
     */
    var bufferedReader = new Ext.ux.data.BufferedJsonReader(readerConfigOptions, recordDef);

    /**
     * Set up your store.
     * An instance of BufferedJsonReader is needed if you want to listen to
     * <tt>versionchange</tt> events.
     * Make sure you set the config option bufferSize high enough
     * (something between 100 and 300  works good).
     */
    return new Ext.ux.grid.BufferedStore({
        autoLoad   : true,
        bufferSize : 500,
        reader     : bufferedReader,
        sortInfo   : {field: 'ID', direction: 'ASC'},
        proxy      :  new Ext.data.MemoryProxy(jsonDataList)
    });
}

/**
 * 通过url异步获取数据
 * @param url http url
 * @param baseParams 对于每次发起http调用都需要传递的基本参数，如：对于翻页查询，每次都需要传递的查询参数
 * @param readerConfigOptions
 * @param recordDef

 */
function createHttpStore(url, baseParams, recordDef, readerConfigOptions) {
    if (!readerConfigOptions.id) {
        readerConfigOptions.id = 'ID';
    }
    readerConfigOptions.root = "returnObject";
    readerConfigOptions.totalProperty = "totalCount";
    return new Ext.data.Store({
        //        url: url,
        proxy: new Ext.data.HttpProxy({
            url: url
        }),
        reader: new Ext.data.JsonReader(readerConfigOptions, recordDef),
        baseParams : baseParams
    });
}



/**
 * 创建 Ext Tree，可以参考 include/include_header.vhtml，显示模块Node Tree
 *
 * @param treeDiv 显示树的div区域
 * @param resultList 域列表
 * @param addLabelEvent 增加label点击事件
 * @param href 是否为TreeNode生成 href
 **/
function createExtTree(elementId, treePanelAttributes, rootNodeAttributes, jsonDataList) {
    treePanelAttributes.el = elementId;
    var tree = new Ext.tree.TreePanel(treePanelAttributes);
    var root = new Ext.tree.TreeNode(rootNodeAttributes);
    tree.setRootNode(root);

    var dataList = jsonDataList;
    for (var j = 0; j < dataList.length; j++) {
        var jsonObj = dataList[j];
        if (!jsonObj.text && jsonObj.name) {
            jsonObj.text = jsonObj.NAME;
        }
        if (jsonObj.ID && !jsonObj.id) { // extjs使用小写 id
            jsonObj.id = jsonObj.ID;
        }
        if (jsonObj.BIND_ACTION) { // 处理 moduleTree
            jsonObj.href = jsonObj.BIND_ACTION + ".do";
        }
        if (j == 0) {
            eval("var node_" + jsonObj.ID + " = new Ext.tree.TreeNode(jsonObj);");
            eval("node_" + jsonObj.ID)
            root.appendChild(eval("node_" + jsonObj.ID));
        }
        else {
            try {
                eval("var node_" + jsonObj.ID + "= new Ext.tree.TreeNode(jsonObj);");
                eval("node_" + jsonObj.PARENT_ID).appendChild(eval("node_" + jsonObj.ID))
            }
            catch(e) {
                eval("var node_" + jsonObj.ID + " = new Ext.tree.TreeNode(jsonObj);");
                root.appendChild(eval("node_" + jsonObj.ID));
            }
        }
    }
    tree.render();
    return tree;
}

/**
 * 创建 checkbox tree
 * @param elementId
 * @param treePanelAttributes
 * @param rootNodeAttributes
 * @param jsonDataList
 */
function createExtCheckboxTree(elementId, treePanelAttributes, rootNodeAttributes, jsonDataList) {

    function expandChecked(node) { //对子节点进行打开、关闭，已加载 TreeNodeUI，否则操作 checkbox 无效
        if (!node.isExpanded()) {
            node.expand(false, false, function() {
                node.collapse(false, false);
            });
        }
        for (var i = 0; i < node.childNodes.length; i++) {
            expandChecked(node.childNodes[i]);
        }
    }
    
    var dataList = jsonDataList;
//    treePanelAttributes.selModel = new Ext.tree.MultiSelectionModel(); // 可以多选
    for (var j = 0; j < dataList.length; j++) {
        var jsonObj = dataList[j];
        if (typeof jsonObj.checked == "undefined") {
            jsonObj.checked = false;
        }
        jsonObj.BIND_ACTION = null; // 不要生成链接
    }
    var tree = createExtTree(elementId, treePanelAttributes, rootNodeAttributes, jsonDataList);
    //强制加载所有子节点
    expandChecked(tree.getRootNode());

    tree.on("checkchange", function(node, checked) {
        //选择所有子节点
        node.cascade(function(theNode) {
            theNode.getUI().toggleCheck(checked);
            return true;
        });
        //选择父节点
        node.bubble(function(theNode) {
            if(theNode == node) { // 如果是自身，不需要处理，因为在 cascade 中已经处理
                return true;
            }
            if (!theNode.parentNode || theNode==tree.getRootNode()) { // 如果没有父节点或者是根节点
                return false;
            }
            if (checked) {
                theNode.getUI().toggleCheck(checked);
                return true;
            }
            else {
                var otherChildSelected = false; //是否有其它子节点选中
                for (var i = 0; i < theNode.childNodes.length; i++) {
                    var cnode = theNode.childNodes[i];
                    if (cnode != node && cnode.getUI().isChecked()) {
                        otherChildSelected = true;
                        break;
                    }
                }
                if (!otherChildSelected) {
                    theNode.getUI().toggleCheck(checked);
                    return true;
                }
                else {
                    return false; //不需要继续向上追溯
                }
            }
        });
    });
    return tree;
}

/**
 * 创建异步更新的Tree
 * @param elementId
 * @param loadURL 用来取子节点的 url
 * @param baseParams 每次调用url时，默认传的参数
 */
function createExtAsyncTree(elementId, treePanelAttributes, rootNodeAttributes, loaderURL, baseParams) {
    treePanelAttributes.el = elementId;
    treePanelAttributes.loader = new Ext.tree.MyTreeLoader({
        dataUrl: loaderURL,
        baseParams: baseParams // custom http params
    });
    var tree = new Ext.tree.TreePanel(treePanelAttributes);
    var root = new Ext.tree.AsyncTreeNode(rootNodeAttributes);
    tree.setRootNode(root);
    tree.render();
    return tree;
}

/**
 * 创建 Ext TreeTable，可以参考 function/node_management.vhtml
 * @param elementId 用于显示 TreeTable 的 div id
 * @param treePanelAttributes tree panel 书香
 * @param columnModel 用于显示 Table 的 columnModel
 * @param rootNodeAttributes root node 属性
 * @param jsonDataList
 */
function createExtColumnTree(elementId, treePanelAttributes, rootNodeAttributes, columnModel, jsonDataList) {
    treePanelAttributes.el = elementId;
    treePanelAttributes.columns = columnModel;
    treePanelAttributes.uiProviders = {'col': Ext.tree.ColumnNodeUI};
    var root = new Ext.tree.TreeNode(rootNodeAttributes);
    var dataList = jsonDataList;
    for (var j = 0; j < dataList.length; j++) {
        var jsonObj = dataList[j];
//        jsonObj.uiProvider = Ext.tree.ColumnNodeUI;
        if (!jsonObject.text && jsonObj.NAME) {
            jsonObj.text = jsonObj.NAME;
        }

        if (jsonObj.ID && !jsonObj.id) { // extjs使用小写 id
            jsonObj.id = jsonObj.ID;
        }
        if (j == 0) {
            eval("var node_" + jsonObj.ID + " = new Ext.tree.TreeNode(jsonObj);");
            eval("node_" + jsonObj.ID)
            root.appendChild(eval("node_" + jsonObj.ID));
        }
        else {
            try {
                eval("var node_" + jsonObj.ID + "= new Ext.tree.TreeNode(jsonObj);");
                eval("node_" + jsonObj.PARENT_ID).appendChild(eval("node_" + jsonObj.ID))
            }
            catch(e) {
                eval("var node_" + jsonObj.ID + " = new Ext.tree.TreeNode(jsonObj);");
                root.appendChild(eval("node_" + jsonObj.ID));
            }
        }
    }
    treePanelAttributes.root = root;
    var columnTree = new Ext.tree.ColumnTree(treePanelAttributes)
    columnTree.render();
    return columnTree;
}

function createExtAsyncColumnTree(elementId, treePanelAttributes, rootNodeAttributes, columnModel, loaderURL, baseParams) {
    if (baseParams == null) {
        baseParams = {};
    }
    treePanelAttributes.el = elementId;
    treePanelAttributes.columns = columnModel;
//    treePanelAttributes.uiProviders = {'col': Ext.tree.ColumnNodeUI}; // 不行，要设置在 TreeLoader 上
    treePanelAttributes.loader = new Ext.tree.MyTreeLoader({
        dataUrl: loaderURL,
        baseParams: baseParams, // custom http params
        uiProviders:{
            'col': Ext.tree.ColumnNodeUI
        }
    });
    treePanelAttributes.root = new Ext.tree.AsyncTreeNode(rootNodeAttributes);
    var tree = new Ext.tree.ColumnTree(treePanelAttributes);
//    tree.setRootNode(root);
    tree.render();
    return tree;
}
/**
 * 创建 extjs Grid
 * @param gridContainerId
 * @param layoutContainerId
 * @param dataSource
 * @param columnModel
 * @param configOptions
 */
function createExtGrid(gridContainerId, columnModel, store, configOptions) {
    store.load();
    if (!configOptions) {
        configOptions = {};
    }
    configOptions.renderTo = gridContainerId;
//    configOptions.el = gridContainerId; // 有了 renderTo，就不能再有 el
    configOptions.store = store;
    configOptions.width = 762;
    configOptions.autoHeight = true;
    configOptions.colModel = columnModel;

    //避免覆盖已经设置的 viewConfig
    if (!configOptions.viewConfig) {
        configOptions.viewConfig = {};
    }
//    configOptions.viewConfig.autoFill = true;
    configOptions.viewConfig.forceFit = true

    var grid = new Ext.grid.GridPanel(configOptions);
    /*
        Ext.BorderLayout.create({
            center: {
                margins:{left:3,top:3,right:3,bottom:3},
                panels: [new Ext.GridPanel(grid)]
            }
        }, layoutContainerId);
    */
    grid.render();
    grid.getSelectionModel().selectFirstRow();
    return grid;
}

function createExtCheckboxGrid(gridContainerId, columnModel, store, configOptions) {
    var sm = new Ext.grid.CheckboxSelectionModel();

    var cmConfig = columnModel.config;
    var newcmconfig = new Array(cmConfig.length + 1);
    newcmconfig[0] = sm;
    for(var i=0; i<cmConfig.length; i++){
        newcmconfig[i+1] = cmConfig[i];
    }
    columnModel.setConfig(newcmconfig);
    store.load();
    if (!configOptions) {
        configOptions = {};
    }

    configOptions.sm = sm;
    configOptions.renderTo = gridContainerId;
//    configOptions.el = gridContainerId; // 有了 renderTo，就不能再有 el
    configOptions.store = store;
    if(!configOptions.width) {
        configOptions.autoWidth = true;
    }
    if(!configOptions.height) {
        configOptions.autoHeight = true;
    }
    configOptions.colModel = columnModel;

    //避免覆盖已经设置的 viewConfig
    if (!configOptions.viewConfig) {
        configOptions.viewConfig = {};
    }
//    configOptions.viewConfig.autoFill = true;
    configOptions.viewConfig.forceFit = true
    var grid = new Ext.grid.GridPanel(configOptions);
    grid.render();
    return grid;
}

/**
 * 创建带分页的 extjs Grid
 * @param gridContainerId
 * @param layoutContainerId
 * @param dataSource
 * @param columnModel
 * @param configOptions
 */
function createExtPagingGrid(gridContainerId, columnModel, store, configOptions, rowsPerPage) {
    if (!rowsPerPage) {
        rowsPerPage = 25; // 默认每页条数
    }
//    alert(store.data);
    if (!configOptions) {
        configOptions = {};
    }
    configOptions.renderTo = gridContainerId;
    configOptions.store = store;
    configOptions.width = 762;
    configOptions.autoHeight = true; // 很重要，否则新加载的数据无法显示
    configOptions.colModel = columnModel;

    //避免覆盖已经设置的 viewConfig
    if (!configOptions.viewConfig) {
        configOptions.viewConfig = {};
    }
//    configOptions.viewConfig.autoFill = true;
    configOptions.viewConfig.forceFit = true
    configOptions.bbar = new Ext.PagingToolbar({
        pageSize: rowsPerPage,
        store: store,
        displayInfo: true,
        displayMsg: "显示 {0} - {1} 条， 共 {2} 条",
        emptyMsg: "没有任何数据"
    })
    var grid = new Ext.grid.GridPanel(configOptions);
    grid.render();
    store.load({params:{start:0, limit:rowsPerPage}});
    grid.getSelectionModel().selectFirstRow();
    return grid;
}

function createExtEditorGrid(gridContainerId, columnModel, store, configOptions) {
    store.load();
    configOptions.renderTo = gridContainerId;
    configOptions.store = store;
    configOptions.width = 762;
    configOptions.autoHeight = true;
    configOptions.colModel = columnModel;
    var grid = new Ext.grid.GridPanel(configOptions);
    /*
        Ext.BorderLayout.create({
            center: {
                margins:{left:3,top:3,right:3,bottom:3},
                panels: [new Ext.GridPanel(grid)]
            }
        }, layoutContainerId);
    */
    grid.render();
    grid.getSelectionModel().selectFirstRow();
    return grid;
}

/**
 * 支持动态渲染的Grid，需要使用BufferedMemoryStore
 * @param gridContainerId
 * @param columnModel
 * @param store
 * @param configOptions
 */
function createExtLiveGrid(gridContainerId, columnModel, store, configOptions){
    // 应该使用 Ext.ux.grid.BufferedStore、Ext.ux.data.BufferedJsonReader 和 MemoryProxy

    /**
     * Here is where the magic happens: BufferedGridView. The nearLimit
     * is a parameter for the predictive fetch algorithm within the view.
     * If your bufferSize is small, set this to a value around a third or a quarter
     * of the store's bufferSize (e.g. a value of 25 for a bufferSize of 100;
     * a value of 100 for a bufferSize of 300).
     * The loadMask is optional but should be used to provide some visual feedback
     * for the user when the store buffers (the loadMask from the GridPanel
     * will only be used for initial loading, sorting and reloading).
     */
    var bufferedView = new Ext.ux.grid.BufferedGridView({
        nearLimit: 100,
        loadMask : {msg : 'Please wait...'}
    });

        /**
     * You can use an instance of BufferedGridToolbar for keeping track of the
     * current scroll position. It also gives you a refresh button and a loading
     * image that gets activated when the store buffers.
     * ...Yeah, I pretty much stole this one from the PagingToolbar!
     */
    var bufferedGridToolbar = new Ext.ux.BufferedGridToolbar({
        view        : bufferedView,
        displayInfo : true
    });

        /**
     * BufferedRowSelectionModel introduces a different selection model and a
     * new <tt>selectiondirty</tt> event.
     * You can keep selections between <b>all</bb> ranges in the grid; records which
     * are currently in the buffer and are selected will be added to the selection
     * model as usual. Rows representing records <b>not</b> loaded in the current
     * buffer will be marked using a predictive index when selected.
     * Selected rows will be successively read into the selection store
     * upon scrolling through the view. However, if any records get added or removed,
     * and selection ranges are pending, the selectiondirty event will be triggered.
     * It is up to the user to either clear the pending selections or continue
     * with requesting the pending selection records from the data repository.
     * To put the whole matter in a nutshell: Selected rows which represent records
     * <b>not</b> in the current data store will be identified by their assumed
     * index in the data repository, and <b>not</b> by their id property.
     * Events such as <tt>versionchange</tt> or <tt>selectiondirty</tt>
     * can help in telling if their positions in the data repository changed.
     */
    var bufferedSelectionModel = new Ext.ux.grid.BufferedRowSelectionModel();

    configOptions.renderTo = gridContainerId;
    configOptions.ds = store;
    configOptions.enableDragDrop = false;
    configOptions.cm = columnModel;
    configOptions.sm = bufferedSelectionModel;
    configOptions.loadMask = {msg : 'Loading...'};
    configOptions.view = bufferedView;
    configOptions.bbar = bufferedGridToolbar;

    var grid = new Ext.grid.GridPanel(configOptions);

    return grid;
}

/**
 * 弹出窗口
 * 
 * @param url
 * @param windowname
 * @param width
 * @param height
 * @param pointX
 * @param pointY
 */
function popupWin(url, windowname, width, height, pointX, pointY) {
    if (!windowname) {
        windowname = "popup";
    }
    if (!width) {
        width = 800;
    }
    if (!height) {
        height = 600;
    }
    if (!pointX) {
        pointX = 120;
    }
    if (!pointY) {
        pointY = 80;
    }
    var attributes = 'width=' + width + ',height=' + height + ',left=' + pointX + ',top=' + pointY + ',screenX=' + pointX + ',screenY=' + pointY + ',scrollbars=yes,resizable=yes,status=yes,depended=yes';
    return window.open(url, windowname, attributes);
}

/**
 * 发起 AJAX 调用，用于异步更新页面某部分内容
 * @param url
 * @param params
 * @param successcallback
 */
//TODO: 实现数据校验以及按钮禁用
function ajaxRequest(url, params, successcallback) {
    //    var ajaxconn = new Ext.data.Connection();
    //    alert("AJAX url: " + url);
    Ext.Ajax.request({
        timeout : 120000,
        url: url, // where to post to..
        params: params, // << key value object with data to send
        method: 'POST',
        success: successcallback,
        failure: function(response, opts) {
            //            Ext.MessageBox.alert("AJAX Failure!", response.responseText);
            var text = response.responseText;
            if (text == null) {
                text = '发生了错误，请查看服务器日志！';
            }
            Ext.MessageBox.show({
                title: "AJAX Failure!",
                msg: response.responseText,
                buttons: Ext.MessageBox.OK,
                animEl: 'mb9',
                maxWidth:1000,
                width:800
                //                fn: showResult,
                //                icon: Ext.get('icons').dom.value
            });
        }

    });
}

/**
 * 使用 AJAX 提交表单，用于异步提交表单
 * @param form
 * @param successcallback
 */
//TODO: 实现数据校验以及按钮禁用
function ajaxSubmit(form, successcallback) {
    //    alert(form.action);
    Ext.Ajax.request({
        timeout : 120000,
        url: form.action, // where to post to..
        form: form,
        method: 'POST',
        success: successcallback,
        failure: function(response, opts) {
            Ext.MessageBox.alert("AJAX Failure!", response.responseText);
        }
    });

}

function alertFailureJSONReponse(message, jsonResponse) {
    alert(message + "\n\n异常：\n" + jsonResponse.exception);
}

function evalExtJSResponse(response){
    return eval('(' + response.responseText + ')');
}
/**
 * 为了支持 TreeLoader 去 jsonReponse.returnObject
 */
Ext.tree.MyTreeLoader = Ext.extend(Ext.tree.TreeLoader, {
    processResponse : function(response, node, callback) {
        var json = response.responseText;
        try {
            var o = eval("(" + json + ")");
            o = o.returnObject; // 使用 returnObject 数据
            node.beginUpdate();
            for (var i = 0, len = o.length; i < len; i++) {
                o[i].uiProvider = 'col'; // 使用 ColumnTree uiProviders
                var n = this.createNode(o[i]);
                if (n) {
                    node.appendChild(n);
                }
            }
            node.endUpdate();
            if (typeof callback == "function") {
                callback(this, node);
            }
        }
        catch(e) {
            this.handleFailure(response);
        }
    }
});

